package com.GXKJ.Test.config;



import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.stat.DruidDataSourceStatManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
import org.springframework.util.StringUtils;

import java.sql.Connection;
import java.sql.DriverManager;
import java.util.Map;
import java.util.Set;
/*
 * @author nongzhiquan
 * @date 2021年05月13日 11:18
 */


public class DynamicDataSource extends AbstractRoutingDataSource {
    private boolean debug = true;
    private final Logger log = LoggerFactory.getLogger(getClass());
    private Map<Object, Object> dynamicTargetDataSources;
    private Object dynamicDefaultTargetDataSource;

    @Override
    protected Object determineCurrentLookupKey() {
        String datasource = DBContextHolder.getDataSource();
        if (!StringUtils.isEmpty(datasource)) {
            Map<Object, Object> dynamicTargetDataSources2 = this.dynamicTargetDataSources;
            if (dynamicTargetDataSources2.containsKey(datasource)) {
                log.info("---当前数据源：" + datasource + "---");
            } else {
                log.info("不存在的数据源：");
            }
        } else {
            log.info("---当前数据源：默认数据源---");
        }
        return datasource;
    }

    @Override
    public void setTargetDataSources(Map<Object, Object> targetDataSources) {
        super.setTargetDataSources(targetDataSources);
        this.dynamicTargetDataSources = targetDataSources;
    }

    // 创建数据源
    private boolean createDataSourc(String datasourceid, String driveClass, String url, String username, String password) {
        try {
            try { // 排除连接不上的错误
                Class.forName(driveClass);
                DriverManager.getConnection(url, username, password);// 相当于连接数据库
            } catch (Exception e) {
                return false;
            }
            DruidDataSource druidDataSource = new DruidDataSource();
            //druidDataSource.setName(key);
            druidDataSource.setUrl(url);
            druidDataSource.setDriverClassName(driveClass);
            druidDataSource.setUsername(username);
            druidDataSource.setPassword(password);
            //初始化时建立物理连接的个数。初始化发生在显示调用init方法，或者第一次getConnection时
            druidDataSource.setInitialSize(10);
            //最大连接池数量
            druidDataSource.setMaxActive(20);
            //获取连接时最大等待时间，单位毫秒。当链接数已经达到了最大链接数的时候，应用如果还要获取链接就会出现等待的现象，等待链接释放并回到链接池，如果等待的时间过长就应该踢掉这个等待，不然应用很可能出现雪崩现象
            druidDataSource.setMaxWait(60000);
            //最小连接池数量
            druidDataSource.setMinIdle(5);
            //String validationQuery = "select 1 from dual";
            //druidDataSource.setValidationQuery(validationQuery);//用来检测连接是否有效的sql，要求是一个查询语句。
            druidDataSource.init();
            this.dynamicTargetDataSources.put("key", druidDataSource);
            setTargetDataSources(this.dynamicTargetDataSources);// 将map赋值给父类的TargetDataSources
            super.afterPropertiesSet();// 将TargetDataSources中的连接信息放入resolvedDataSources管理
            log.info("数据源初始化成功----->"+druidDataSource.dump());
            //log.info(key+"数据源的概况："+druidDataSource.dump());
            return true;
        } catch (Exception e) {
            log.error(e + "");
            return false;
        }
    }

    // 创建数据源
//    public boolean createDataSourc(String key,String driveClass,String datasourceid,String url,String dbname,String username,String password) {
//        try {
//            try { // 排除连接不上的错误
//                Class.forName(driveClass);
//                DriverManager.getConnection(url, username, password);// 相当于连接数据库
//            } catch (Exception e) {
//                return false;
//            }
//            DruidDataSource druidDataSource = new DruidDataSource();
//            druidDataSource.setName(key);
//            druidDataSource.setUrl(url);
//            druidDataSource.setDriverClassName(driveClass);
//            druidDataSource.setUsername(username);
//            druidDataSource.setPassword(password);
//            //初始化时建立物理连接的个数。初始化发生在显示调用init方法，或者第一次getConnection时
//            druidDataSource.setInitialSize(1);
//            //最大连接池数量
//            druidDataSource.setMaxActive(20);
//            //获取连接时最大等待时间，单位毫秒。当链接数已经达到了最大链接数的时候，应用如果还要获取链接就会出现等待的现象，等待链接释放并回到链接池，如果等待的时间过长就应该踢掉这个等待，不然应用很可能出现雪崩现象
//            druidDataSource.setMaxWait(60000);
//            //最小连接池数量
//            druidDataSource.setMinIdle(5);
//            dynamicTargetDataSources.put(key, druidDataSource);
//            setTargetDataSources(dynamicTargetDataSources);// 将map赋值给父类的TargetDataSources
//            super.afterPropertiesSet();// 将TargetDataSources中的连接信息放入resolvedDataSources管理
//            log.info(druidDataSource + "数据源初始化成功");
//            //log.info(key+"数据源的概况："+druidDataSource.dump());
//            return true;
//        } catch (Exception e) {
//            log.error(e + "");
//            return false;
//        }
//    }

    // 删除数据源
    public boolean delDatasources(String datasourceid) {
        log.info("开始删除数据源");
        Map<Object, Object> dynamicTargetDataSources2 = dynamicTargetDataSources;
        if (dynamicTargetDataSources2.containsKey(datasourceid)) {
            Set<DruidDataSource> druidDataSourceInstances = DruidDataSourceStatManager.getDruidDataSourceInstances();
            for (DruidDataSource l : druidDataSourceInstances) {
                if (datasourceid.equals(l.getName())) {
                    dynamicTargetDataSources2.remove(datasourceid);
                    DruidDataSourceStatManager.removeDataSource(l);
                    // 将map赋值给父类的TargetDataSources
                    setTargetDataSources(dynamicTargetDataSources2);
                    super.afterPropertiesSet();// 将TargetDataSources中的连接信息放入resolvedDataSources管理
                    log.info("完成!");
                    return true;
                }
            }
            return false;
        } else {
            return false;
        }

    }
    //测试数据源连接是否有效
    public boolean testDatasource(String datasourceid, String driveClass, String url, String username, String password) {
        try {
            Class.forName(driveClass);
            DriverManager.getConnection(url, username, password);
            log.info("测试数据源连接是有效的");
            return true;
        } catch (Exception e) {
            log.info("测试数据源连接是无效的");
            return false;
        }
    }

    @Override
    public void setDefaultTargetDataSource(Object defaultTargetDataSource) {
        super.setDefaultTargetDataSource(defaultTargetDataSource);
        this.dynamicDefaultTargetDataSource = defaultTargetDataSource;
    }

    /**
     * @param debug the debug to set
     */
    public void setDebug(boolean debug) {

        this.debug = debug;
    }

    /**
     * @return the debug
     */
    public boolean isDebug() {

        return debug;
    }

    /**
     * @return the dynamicTargetDataSources
     */
    public Map<Object, Object> getDynamicTargetDataSources() {

        return dynamicTargetDataSources;
    }

    /**
     *
     * @param dynamicTargetDataSources the dynamicTargetDataSources to set
     */
    public void setDynamicTargetDataSources(Map<Object, Object> dynamicTargetDataSources) {
        this.dynamicTargetDataSources = dynamicTargetDataSources;
    }

    /**
     * @return the dynamicDefaultTargetDataSource
     */
    public Object getDynamicDefaultTargetDataSource() {
        return dynamicDefaultTargetDataSource;
    }

    /**
     * @param dynamicDefaultTargetDataSource the dynamicDefaultTargetDataSource to set
     */
    public void setDynamicDefaultTargetDataSource(Object dynamicDefaultTargetDataSource) {
        this.dynamicDefaultTargetDataSource = dynamicDefaultTargetDataSource;
    }

    public boolean createDataSourceWithCheck(String datasourceid, String url, String dbname, String username, String password) throws Exception {
 //       String datasourceId = databasesource.getDatasourceid();
        log.info("正在检查数据源："+datasourceid+"");
        Map<Object, Object> dynamicTargetDataSources2 = this.dynamicTargetDataSources;
        if (dynamicTargetDataSources2.containsKey(datasourceid)) {
            log.info("数据源" + datasourceid + "之前已经创建，准备测试数据源是否正常...");
            DruidDataSource druidDataSource = (DruidDataSource) dynamicTargetDataSources2.get(datasourceid);
            boolean rightFlag = true;
            Connection connection = null;
            try {
                log.info(datasourceid + "数据源的概况->当前闲置连接数：" + druidDataSource.getPoolingCount());
                long activeCount = druidDataSource.getActiveCount();
                log.info(datasourceid + "数据源的概况->当前活动连接数：" + activeCount);
                if (activeCount > 0) {
                    log.info(datasourceid + "数据源的概况->活跃连接堆栈信息：" + druidDataSource.getActiveConnectionStackTrace());
                }
                log.info("准备获取数据库连接...");
                connection = druidDataSource.getConnection();
                log.info("数据源" + datasourceid + "正常");
            } catch (Exception e) {
                //把异常信息打印到日志文件
                log.error(e.getMessage(), e);
                rightFlag = false;
                log.info("缓存数据源" + datasourceid + "已失效，准备删除...");
                if (delDatasources(datasourceid)) {
                    log.info("缓存数据源删除成功");
                } else {
                    log.info("缓存数据源删除失败");
                }
            } finally {
                if (null != connection) {
                    connection.close();
                }
            }
            if (rightFlag) {
                log.info("不需要重新创建数据源");
            } else {
                log.info("准备重新创建数据源...");
                createDataSourced(datasourceid,url, dbname,username, password);
                log.info("重新创建数据源完成");
            }
        }
        if (createDataSourced(datasourceid,url,dbname,username,password)==true){
            log.info("准备切换数据源......");
            return true;
        }else {
            log.info("检查数据源有问题,请检查输入的数据源是否正确!");
            return false;
        }
    }

    public boolean createDataSourced(String datasourceid,String url,String dbname,String username,String password) {
       //String datasourceId = databasesource.getDatasourceid();
        log.info("准备创建数据源:"+datasourceid);
//        String url = databasesource.getUrl();
//        String databasetype = databasesource.getDbname();
//        String username = databasesource.getUsername();
//        String password = databasesource.getPassword();
        String driveClass = "com.mysql.jdbc.Driver";
        if(testDatasource(datasourceid,driveClass,url,username,password)) {
            boolean result = this.createDataSourc(datasourceid,driveClass,url,username,password);
            System.out.println("创建数据源成功!");
            if(!result) {
                log.error("数据源"+datasourceid+"配置正确，但是创建失败");
          }
        }else {
            log.error("数据源配置有错误");
            DBContextHolder.clearDataSource();
            return false;
        }
        return true;
    }



    public static class DBContextHolder{

        private final static Logger log = LoggerFactory.getLogger(DBContextHolder.class);
        // 对当前线程的操作-线程安全的
        private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>();

        // 调用此方法，切换数据源
        public static boolean setDataSource(String dataSource) {
            contextHolder.set(dataSource);
            log.info("已切换到数据源:{}",dataSource);
            return true;
        }

        // 获取数据源
        public static String getDataSource() {
            return contextHolder.get();
        }


        // 删除数据源
        public static void clearDataSource() {
            contextHolder.remove();
            log.info("已切换到主数据源");
        }
    }
}

